/*
 * i2c_slave.cpp
 *
 *  Created on: Jan 11, 2014
 *      Author: bohni
 */


#include "i2c_slave.h"

volatile uint8_t i2c_buffer[I2C_BUFFER_SIZE];
volatile uint8_t i2c_buf_ptr;
volatile uint8_t i2c_busy;
volatile uint8_t i2c_state;

void i2c_slave_init() {

	TWAR = I2C_SLAVE_ADR;


	// PRESCALER = 0
	TWSR = 0;
	TWBR = (( F_CPU / I2C_FREQ ) - 16 ) / 2 ;

	TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE);

}


ISR( TWI_vect ){
	switch ( TWSR & 0xFC ) {

	case TW_ST_SLA_ACK:
		i2c_buf_ptr = 0;
		/* no break */
	case TW_ST_DATA_ACK:
		TWDR = i2c_buffer[i2c_buf_ptr];
		i2c_buf_ptr++;
	    TWCR = (1<<TWEN)| (1<<TWIE)|(1<<TWINT)| (1<<TWEA);
	    i2c_busy = 1;
	    break;
	case TW_ST_DATA_NACK:
		TWCR = (1<<TWEN)| (1<<TWIE)|(1<<TWINT)| (1<<TWEA);
		i2c_busy = 0;
		break;
	case TW_SR_GCALL_ACK:
	case TW_SR_SLA_ACK:

		i2c_buf_ptr = 0;

	    TWCR = (1<<TWEN)| (1<<TWIE)|(1<<TWINT)| (1<<TWEA);
	    i2c_busy = 1;
	    break;

	case TW_SR_DATA_ACK:
	case TW_SR_GCALL_DATA_ACK:
		i2c_state = TW_SR_DATA_ACK;
		i2c_buffer[i2c_buf_ptr] = TWDR;
		i2c_buf_ptr++;

		TWCR = (1<<TWEN)| (1<<TWIE)|(1<<TWINT)| (1<<TWEA);
		i2c_busy = 1;

		break;

	case TW_SR_STOP:
		TWCR = (1<<TWEN)| (1<<TWIE)|(1<<TWINT)| (1<<TWEA);
		i2c_busy = 0;
		break;

	case TW_SR_DATA_NACK:
	case TW_SR_GCALL_DATA_NACK:
	case TW_ST_LAST_DATA:
	case TW_BUS_ERROR:
		i2c_state = ( TWSR & 0xFC );
		TWCR = (1<<TWINT);
		break;

	default:
		i2c_state = ( TWSR & 0xFC );
		TWCR = (1<<TWEN)| (1<<TWIE)|(1<<TWINT)| (1<<TWEA);
		i2c_busy = 0;
	}
}
